﻿// Jinx AJAX Framework
// Copyright (C) 2008 Blake Hegerle
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Linq;

namespace Core
{
#pragma warning disable 660, 661

    public abstract class Tuple
    {
        private object[] cm;
        protected abstract object[] Members { get; }

        private object[] CachedMembers
        {
            get
            {
                if (cm == null)
                    cm = Members;
                return cm;
            }
        }

        public static Tuple<T1> New<T1>(T1 i1)
        {
            return new Tuple<T1>(i1);
        }

        public static Tuple<T1, T2> New<T1, T2>(T1 i1, T2 i2)
        {
            return new Tuple<T1, T2>(i1, i2);
        }

        public static Tuple<T1, T2, T3> New<T1, T2, T3>(T1 i1, T2 i2, T3 i3)
        {
            return new Tuple<T1, T2, T3>(i1, i2, i3);
        }

        public static Tuple<T1, T2, T3, T4> New<T1, T2, T3, T4>(T1 i1, T2 i2, T3 i3, T4 i4)
        {
            return new Tuple<T1, T2, T3, T4>(i1, i2, i3, i4);
        }

        public override bool Equals(object that)
        {
            if (that == null)
                return false;

            if (GetType() != that.GetType())
                return false;

            if (that is Tuple)
                return ReferenceEquals(this, that) ||
                       ImmutableUtil.ArrayEquals(CachedMembers, (that as Tuple).CachedMembers);
            return false;
        }

        public override int GetHashCode()
        {
            return ImmutableUtil.ArrayHash(CachedMembers);
        }

        public override string ToString()
        {
            var Members = from M in CachedMembers
                          select M == null ? "null" : M.ToString();

            return "{" + Members.Join(", ") + "}";
        }

        protected static void NullCheck(object o)
        {
            if (o == null)
                throw new ArgumentNullException();
        }
    }

    public class Tuple<T1> : Tuple
    {
        public readonly T1 Item1;

        public Tuple(T1 t1)
        {
            Item1 = t1;
        }

        protected override object[] Members
        {
            get { return new object[] {Item1}; }
        }

        public static bool operator ==(Tuple<T1> left, Tuple<T1> right)
        {
            var NullCheck = ImmutableUtil.NullCheck(left, right);
            return NullCheck.HasValue ? NullCheck.Value : left.Equals(right);
        }

        public static bool operator !=(Tuple<T1> left, Tuple<T1> right)
        {
            return !(left == right);
        }
    }

    public class Tuple<T1, T2> : Tuple<T1>
    {
        public readonly T2 Item2;

        public Tuple(T1 t1, T2 t2)
            : base(t1)
        {
            Item2 = t2;
        }

        protected override object[] Members
        {
            get { return new object[] {Item1, Item2}; }
        }

        public static bool operator ==(Tuple<T1, T2> left, Tuple<T1, T2> right)
        {
            var NullCheck = ImmutableUtil.NullCheck(left, right);
            return NullCheck.HasValue ? NullCheck.Value : left.Equals(right);
        }

        public static bool operator !=(Tuple<T1, T2> left, Tuple<T1, T2> right)
        {
            return !(left == right);
        }
    }

    public class Tuple<T1, T2, T3> : Tuple<T1, T2>
    {
        public readonly T3 Item3;

        public Tuple(T1 t1, T2 t2, T3 t3)
            : base(t1, t2)
        {
            Item3 = t3;
        }

        protected override object[] Members
        {
            get { return new object[] {Item1, Item2, Item3}; }
        }

        public static bool operator ==(Tuple<T1, T2, T3> left, Tuple<T1, T2, T3> right)
        {
            var NullCheck = ImmutableUtil.NullCheck(left, right);
            return NullCheck.HasValue ? NullCheck.Value : left.Equals(right);
        }

        public static bool operator !=(Tuple<T1, T2, T3> left, Tuple<T1, T2, T3> right)
        {
            return !(left == right);
        }
    }

    public class Tuple<T1, T2, T3, T4> : Tuple<T1, T2, T3>
    {
        public readonly T4 Item4;

        public Tuple(T1 t1, T2 t2, T3 t3, T4 t4)
            : base(t1, t2, t3)
        {
            Item4 = t4;
        }

        protected override object[] Members
        {
            get { return new object[] {Item1, Item2, Item3, Item4}; }
        }

        public static bool operator ==(Tuple<T1, T2, T3, T4> left, Tuple<T1, T2, T3, T4> right)
        {
            var NullCheck = ImmutableUtil.NullCheck(left, right);
            return NullCheck.HasValue ? NullCheck.Value : left.Equals(right);
        }

        public static bool operator !=(Tuple<T1, T2, T3, T4> left, Tuple<T1, T2, T3, T4> right)
        {
            return !(left == right);
        }
    }

    public class Tuple<T1, T2, T3, T4, T5> : Tuple<T1, T2, T3, T4>
    {
        public readonly T5 Item5;

        public Tuple(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5)
            : base(t1, t2, t3, t4)
        {
            Item5 = t5;
        }

        protected override object[] Members
        {
            get { return new object[] {Item1, Item2, Item3, Item4, Item5}; }
        }

        public static bool operator ==(Tuple<T1, T2, T3, T4, T5> left, Tuple<T1, T2, T3, T4, T5> right)
        {
            var NullCheck = ImmutableUtil.NullCheck(left, right);
            return NullCheck.HasValue ? NullCheck.Value : left.Equals(right);
        }

        public static bool operator !=(Tuple<T1, T2, T3, T4, T5> left, Tuple<T1, T2, T3, T4, T5> right)
        {
            return !(left == right);
        }
    }

    public class Tuple<T1, T2, T3, T4, T5, T6> : Tuple<T1, T2, T3, T4, T5>
    {
        public readonly T6 Item6;

        public Tuple(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6)
            : base(t1, t2, t3, t4, t5)
        {
            Item6 = t6;
        }

        protected override object[] Members
        {
            get { return new object[] {Item1, Item2, Item3, Item4, Item5, Item6}; }
        }

        public static bool operator ==(Tuple<T1, T2, T3, T4, T5, T6> left, Tuple<T1, T2, T3, T4, T5, T6> right)
        {
            var NullCheck = ImmutableUtil.NullCheck(left, right);
            return NullCheck.HasValue ? NullCheck.Value : left.Equals(right);
        }

        public static bool operator !=(Tuple<T1, T2, T3, T4, T5, T6> left, Tuple<T1, T2, T3, T4, T5, T6> right)
        {
            return !(left == right);
        }
    }
#pragma warning restore
}